/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2009 - 2012 Luca Mingardi.
 *
 * This file is part of jeeObserver.
 *
 * JeeObserver is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * JeeObserver is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package jeeobserver.server;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import jeeobserver.ActionObserver;
import jeeobserver.HardDiskObserver;
import jeeobserver.HttpSessionObserver;
import jeeobserver.JvmObserver;
import jeeobserver.server.Statistics.DateStatistics;
import jeeobserver.server.Statistics.NumberRangeStatistics;
import jeeobserver.server.Statistics.NumberStatistics;
import jeeobserver.server.Statistics.SamplingStatistics;
import jeeobserver.server.settings.Settings;
import jeeobserver.server.settings.TimeSchedule;

/**
 * The Class DefaultDatabaseHandler.
 *
 * @author Luca Mingardi
 * @version 4.0
 */
public class FileDatabaseHandler implements DatabaseHandler {

	 public static final String TIMER_TASK_NAME = "JOS_TIMER_TASK";

	 /** The Constant DATABASE_PATH_PARAMETER. */
	 public static final String PATH_PARAMETER = "JOS_DATABASE_PATH";

	 /** The Constant ACTION_SAMPLING_PERIOD_PARAMETER. */
	 public static final String ACTION_SAMPLING_PERIOD_PARAMETER = "JOS_DATABASE_ACTION_SAMPLING_PERIOD";

	 /** The Constant HTTP_SESSION_SAMPLING_PERIOD_PARAMETER. */
	 public static final String HTTP_SESSION_SAMPLING_PERIOD_PARAMETER = "JOS_DATABASE_HTTP_SESSION_SAMPLING_PERIOD";

	 /** The Constant JVM_SAMPLING_PERIOD_PARAMETER. */
	 public static final String JVM_SAMPLING_PERIOD_PARAMETER = "JOS_DATABASE_JVM_SAMPLING_PERIOD";

	 /** The Constant HARD_DISK_SAMPLING_PERIOD_PARAMETER. */
	 public static final String HARD_DISK_SAMPLING_PERIOD_PARAMETER = "JOS_DATABASE_HARD_DISK_SAMPLING_PERIOD";

	 /** The Constant SAMPLING_PERIOD_SECOND. */
	 public static final String SAMPLING_PERIOD_MILLISECOND_ALIAS = "SECOND";

	 /** The Constant SAMPLING_PERIOD_SECOND. */
	 public static final String SAMPLING_PERIOD_SECOND_ALIAS = "SECOND";

	 /** The Constant SAMPLING_PERIOD_MINUTE. */
	 public static final String SAMPLING_PERIOD_MINUTE_ALIAS = "MINUTE";

	 /** The Constant SAMPLING_PERIOD_HOUR. */
	 public static final String SAMPLING_PERIOD_HOUR_ALIAS = "HOUR";

	 /** The Constant SAMPLING_PERIOD_DAY. */
	 public static final String SAMPLING_PERIOD_DAY_ALIAS = "DAY";

	 /** The Constant SAMPLING_PERIOD_MILLISECOND. */
	 public static final int SAMPLING_PERIOD_MILLISECOND = 1;

	 /** The Constant SAMPLING_PERIOD_SECOND. */
	 public static final int SAMPLING_PERIOD_SECOND = 2;

	 /** The Constant SAMPLING_PERIOD_MINUTE. */
	 public static final int SAMPLING_PERIOD_MINUTE = 3;

	 /** The Constant SAMPLING_PERIOD_HOUR. */
	 public static final int SAMPLING_PERIOD_HOUR = 4;

	 /** The Constant SAMPLING_PERIOD_DAY. */
	 public static final int SAMPLING_PERIOD_DAY = 5;

	 /** The Constant DATABASE_PATH_PARAMETER. */
	 public static final String DEFAULT_PATH = "JEEOBSERVER_SERVER_" + JeeObserverServerContext.VERSION[0] + "_" + JeeObserverServerContext.VERSION[1];

	 /** The Constant DEFAULT_ACTION_SAMPLING_PERIOD. */
	 public static final int DEFAULT_ACTION_SAMPLING_PERIOD = SAMPLING_PERIOD_MINUTE;

	 /** The Constant DEFAULT_ACTION_SAMPLING_PERIOD. */
	 public static final int DEFAULT_JVM_SAMPLING_PERIOD = SAMPLING_PERIOD_MINUTE;

	 /** The Constant DEFAULT_ACTION_SAMPLING_PERIOD. */
	 public static final int DEFAULT_HTTP_SESSION_SAMPLING_PERIOD = SAMPLING_PERIOD_HOUR;

	 /** The Constant DEFAULT_ACTION_SAMPLING_PERIOD. */
	 public static final int DEFAULT_HARD_DISK_SAMPLING_PERIOD = SAMPLING_PERIOD_MINUTE;

	 private Timer timer;

	 private FileDatabaseHandlerHardDisk databaseHandlerHardDisk;

	 private FileDatabaseHandlerHttpSession databaseHandlerHttpSession;

	 private FileDatabaseHandlerJvm databaseHandlerJvm;

	 private FileDatabaseHandlerAction databaseHandlerAction;

	 private FileDatabaseHandlerSettings databaseHandlerSettings;

	 public FileDatabaseHandler(Map<String, String> parameters) throws JeeObserverServerException {



			String path = FileDatabaseHandler.DEFAULT_PATH;
			if (parameters != null && parameters.containsKey(FileDatabaseHandler.PATH_PARAMETER)) {
				 path = parameters.get(FileDatabaseHandler.PATH_PARAMETER);
			} else {
				 JeeObserverServerContext.logger.log(Level.WARNING, "Parameter " + FileDatabaseHandler.PATH_PARAMETER + " not found, using default {0}.", FileDatabaseHandler.DEFAULT_PATH);
			}


			final Map<String, Integer> samplingPeriods = new HashMap<String, Integer>();
			samplingPeriods.put(FileDatabaseHandler.SAMPLING_PERIOD_MILLISECOND_ALIAS, FileDatabaseHandler.SAMPLING_PERIOD_MILLISECOND);
			samplingPeriods.put(FileDatabaseHandler.SAMPLING_PERIOD_SECOND_ALIAS, FileDatabaseHandler.SAMPLING_PERIOD_SECOND);
			samplingPeriods.put(FileDatabaseHandler.SAMPLING_PERIOD_MINUTE_ALIAS, FileDatabaseHandler.SAMPLING_PERIOD_MINUTE);
			samplingPeriods.put(FileDatabaseHandler.SAMPLING_PERIOD_HOUR_ALIAS, FileDatabaseHandler.SAMPLING_PERIOD_HOUR);
			samplingPeriods.put(FileDatabaseHandler.SAMPLING_PERIOD_DAY_ALIAS, FileDatabaseHandler.SAMPLING_PERIOD_DAY);
			samplingPeriods.put(String.valueOf(FileDatabaseHandler.SAMPLING_PERIOD_MILLISECOND), FileDatabaseHandler.SAMPLING_PERIOD_MILLISECOND);
			samplingPeriods.put(String.valueOf(FileDatabaseHandler.SAMPLING_PERIOD_SECOND), FileDatabaseHandler.SAMPLING_PERIOD_SECOND);
			samplingPeriods.put(String.valueOf(FileDatabaseHandler.SAMPLING_PERIOD_MINUTE), FileDatabaseHandler.SAMPLING_PERIOD_MINUTE);
			samplingPeriods.put(String.valueOf(FileDatabaseHandler.SAMPLING_PERIOD_HOUR), FileDatabaseHandler.SAMPLING_PERIOD_HOUR);
			samplingPeriods.put(String.valueOf(FileDatabaseHandler.SAMPLING_PERIOD_DAY), FileDatabaseHandler.SAMPLING_PERIOD_DAY);

			int actionSamplingPeriod = FileDatabaseHandler.SAMPLING_PERIOD_MINUTE;

			int jvmSamplingPeriod = FileDatabaseHandler.SAMPLING_PERIOD_MINUTE;

			int httpSessionSamplingPeriod = FileDatabaseHandler.SAMPLING_PERIOD_HOUR;

			int hardDiskSamplingPeriod = FileDatabaseHandler.SAMPLING_PERIOD_MINUTE;


			if (parameters.containsKey(FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER)) {
				 try {
						if (samplingPeriods.containsKey(parameters.get(FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER))) {
							 actionSamplingPeriod = samplingPeriods.get(parameters.get(FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER));
						} else {
							 JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter {0} = {1} is not a valid. (Available values: {2} | {3} | {4} | {5})", new Object[]{FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER, parameters.get(FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER), FileDatabaseHandler.SAMPLING_PERIOD_SECOND, FileDatabaseHandler.SAMPLING_PERIOD_MINUTE, FileDatabaseHandler.SAMPLING_PERIOD_HOUR, FileDatabaseHandler.SAMPLING_PERIOD_DAY});
						}
				 } catch (final NumberFormatException e) {
						JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter " + FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER + " = {0} is not a number.", parameters.get(FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER));
				 }
			} else {
				 JeeObserverServerContext.logger.log(Level.FINE, "Parameter " + FileDatabaseHandler.ACTION_SAMPLING_PERIOD_PARAMETER + " not found, using default {0}.", FileDatabaseHandler.DEFAULT_ACTION_SAMPLING_PERIOD);
			}

			if (parameters.containsKey(FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER)) {
				 try {
						if (samplingPeriods.containsKey(parameters.get(FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER))) {
							 jvmSamplingPeriod = samplingPeriods.get(parameters.get(FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER));
						} else {
							 JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter {0} = {1} is not a valid. (Available values: {2} | {3} | {4} | {5})", new Object[]{FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER, parameters.get(FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER), FileDatabaseHandler.SAMPLING_PERIOD_SECOND, FileDatabaseHandler.SAMPLING_PERIOD_MINUTE, FileDatabaseHandler.SAMPLING_PERIOD_HOUR, FileDatabaseHandler.SAMPLING_PERIOD_DAY});
						}
				 } catch (final NumberFormatException e) {
						JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter " + FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER + " = {0} is not a number.", parameters.get(FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER));
				 }
			} else {
				 JeeObserverServerContext.logger.log(Level.FINE, "Parameter " + FileDatabaseHandler.JVM_SAMPLING_PERIOD_PARAMETER + " not found, using default {0}.", FileDatabaseHandler.DEFAULT_JVM_SAMPLING_PERIOD);
			}

			if (parameters.containsKey(FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER)) {
				 try {
						if (samplingPeriods.containsKey(parameters.get(FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER))) {
							 httpSessionSamplingPeriod = samplingPeriods.get(parameters.get(FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER));
						} else {
							 JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter {0} = {1} is not a valid. (Available values: {2} | {3} | {4} | {5})", new Object[]{FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER, parameters.get(FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER), FileDatabaseHandler.SAMPLING_PERIOD_SECOND, FileDatabaseHandler.SAMPLING_PERIOD_MINUTE, FileDatabaseHandler.SAMPLING_PERIOD_HOUR, FileDatabaseHandler.SAMPLING_PERIOD_DAY});
						}
				 } catch (final NumberFormatException e) {
						JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter " + FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER + " = {0} is not a number.", parameters.get(FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER));
				 }
			} else {
				 JeeObserverServerContext.logger.log(Level.FINE, "Parameter " + FileDatabaseHandler.HTTP_SESSION_SAMPLING_PERIOD_PARAMETER + " not found, using default {0}.", FileDatabaseHandler.DEFAULT_HARD_DISK_SAMPLING_PERIOD);
			}

			if (parameters.containsKey(FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER)) {
				 try {
						if (samplingPeriods.containsKey(parameters.get(FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER))) {
							 hardDiskSamplingPeriod = samplingPeriods.get(parameters.get(FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER));
						} else {
							 JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter {0} = {1} is not a valid. (Available values: {2} | {3} | {4} | {5})", new Object[]{FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER, parameters.get(FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER), FileDatabaseHandler.SAMPLING_PERIOD_SECOND, FileDatabaseHandler.SAMPLING_PERIOD_MINUTE, FileDatabaseHandler.SAMPLING_PERIOD_HOUR, FileDatabaseHandler.SAMPLING_PERIOD_DAY});
						}
				 } catch (final NumberFormatException e) {
						JeeObserverServerContext.logger.log(Level.SEVERE, "Parameter " + FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER + " = {0} is not a number.", parameters.get(FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER));
				 }
			} else {
				 JeeObserverServerContext.logger.log(Level.FINE, "Parameter " + FileDatabaseHandler.HARD_DISK_SAMPLING_PERIOD_PARAMETER + " not found, using default {0}.", FileDatabaseHandler.DEFAULT_HARD_DISK_SAMPLING_PERIOD);
			}



			//Create sub directories
			File pathFolder = new File(path);
			if (!pathFolder.exists()) {
				 pathFolder.mkdir();
				 JeeObserverServerContext.logger.log(Level.INFO, "Path {0} created because does not exists.", pathFolder.getAbsolutePath());
			}

			File dataFolder = new File(pathFolder.getAbsolutePath() + File.separator + "data");
			if (!dataFolder.exists()) {
				 dataFolder.mkdir();
				 JeeObserverServerContext.logger.log(Level.FINE, "Path {0} created because does not exists.", dataFolder.getAbsolutePath());
			}

			File settingsFolder = new File(pathFolder.getAbsolutePath() + File.separator + "settings");
			if (!settingsFolder.exists()) {
				 settingsFolder.mkdir();
				 JeeObserverServerContext.logger.log(Level.FINE, "Path {0} created because does not exists.", settingsFolder.getAbsolutePath());
			}

			File logFolder = new File(pathFolder.getAbsolutePath() + File.separator + "log");
			if (!logFolder.exists()) {
				 logFolder.mkdir();
				 JeeObserverServerContext.logger.log(Level.FINE, "Path {0} created because does not exists.", logFolder.getAbsolutePath());
			}


			try {
				 System.out.println("---1");
				 this.databaseHandlerJvm = new FileDatabaseHandlerJvm(dataFolder.getAbsolutePath() + File.separator, jvmSamplingPeriod);
				 System.out.println("---2");
				 this.databaseHandlerHttpSession = new FileDatabaseHandlerHttpSession(dataFolder.getAbsolutePath() + File.separator, httpSessionSamplingPeriod);
				 System.out.println("---3");
				 this.databaseHandlerHardDisk = new FileDatabaseHandlerHardDisk(dataFolder.getAbsolutePath() + File.separator, hardDiskSamplingPeriod);
				 System.out.println("---4");
				 this.databaseHandlerAction = new FileDatabaseHandlerAction(dataFolder.getAbsolutePath() + File.separator, actionSamplingPeriod);
				 System.out.println("---5");
				 this.databaseHandlerSettings = new FileDatabaseHandlerSettings(settingsFolder.getAbsolutePath() + File.separator);

			} catch (IOException e) {
				 throw new JeeObserverServerException("FileDatabaseHandler initialization error.", e);
			}


			// Start timer task
			this.timer = new Timer(FileDatabaseHandler.TIMER_TASK_NAME, true);
			this.timer.schedule(new DatabaseHandlerTimerTask(), DatabaseHandlerTimerTask.TIMER_INTERVAL, DatabaseHandlerTimerTask.TIMER_INTERVAL);
	 }

	 //Action
	 @Override
	 public void persistActionStatistics(Collection<ActionObserver> observers) throws JeeObserverServerException {

			try {
				 this.databaseHandlerAction.persistStatistics(observers);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error persisting Action statistics.", e);
			}
	 }

	 @Override
	 public void deleteActionStatistics(ActionParameters.DeleteStatisticsParameter parameters) throws JeeObserverServerException {
			try {
				 this.databaseHandlerAction.deleteStatistics(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error deleting Action statistics.", e);
			}
	 }

	 @Override
	 public Collection<ActionStatistics> searchActionStatistics(ActionParameters.SearchStatisticsParameter parameters) throws JeeObserverServerException {
			try {
				 return this.databaseHandlerAction.searchStatistics(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching Action statistics.", e);
			}
	 }

	 @Override
	 public Collection<ActionStatistics.Element> searchActionElements(ActionParameters.SearchElementsParameter parameters) throws JeeObserverServerException {

			try {
				 return this.databaseHandlerAction.searchElements(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching Action elements.", e);
			}
	 }

	 //JVM
	 @Override
	 public void persistJvmStatistics(Collection<JvmObserver> observers) throws JeeObserverServerException {
			try {
				 this.databaseHandlerJvm.persistStatistics(observers);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error persisting JVM statistics.", e);
			}
	 }

	 @Override
	 public void deleteJvmStatistics(JvmParameters.DeleteStatisticsParameter parameters) throws JeeObserverServerException {

			try {
				 this.databaseHandlerJvm.deleteStatistics(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error deleting JVM statistics.", e);
			}
	 }

	 @Override
	 public Collection<JvmStatistics.Element> searchJvmElements(JvmParameters.SearchElementsParameter parameters) throws JeeObserverServerException {
			try {
				 return this.databaseHandlerJvm.searchElements(parameters);
			} catch (final Exception e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching JVM elements.", e);
			}


	 }

	 @Override
	 public Collection<JvmStatistics> searchJvmStatistics(JvmParameters.SearchStatisticsParameter parameters) throws JeeObserverServerException {

			try {
				 return this.databaseHandlerJvm.searchStatistics(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching JVM statistics.", e);
			}


	 }

	 //Http Session
	 @Override
	 public void persistHttpSessionStatistics(Collection<HttpSessionObserver> observers) throws JeeObserverServerException {

			try {
				 this.databaseHandlerHttpSession.persistStatistics(observers);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error persisting Http Session statistics.", e);
			}
	 }

	 @Override
	 public void deleteHttpSessionStatistics(HttpSessionParameters.DeleteStatisticsParameter parameters) throws JeeObserverServerException {

			try {
				 this.databaseHandlerHttpSession.deleteStatistics(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error deleting Http Session statistics.", e);
			}
	 }

	 @Override
	 public Collection<HttpSessionStatistics.Element> searchHttpSessionElements(HttpSessionParameters.SearchElementsParameter parameters) throws JeeObserverServerException {

			try {
				 return this.databaseHandlerHttpSession.searchElements(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching Http Session elements.", e);
			}
	 }

	 @Override
	 public Collection<HttpSessionStatistics> searchHttpSessionStatistics(HttpSessionParameters.SearchStatisticsParameter parameters) throws JeeObserverServerException {

			try {
				 return this.databaseHandlerHttpSession.searchStatistics(parameters);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching Http session statistics.", e);
			}
	 }

	 //Hard Disk
	 @Override
	 public void persistHardDiskStatistics(Collection<HardDiskObserver> observers) throws JeeObserverServerException {

			try {
				 databaseHandlerHardDisk.persistStatistics(observers);
			} catch (Exception e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error persisting Hard Disk statistics.", e);
			}
	 }

	 @Override
	 public void deleteHardDiskStatistics(HardDiskParameters.DeleteStatisticsParameter parameters) throws JeeObserverServerException {

			try {
				 this.databaseHandlerHardDisk.deleteStatistics(parameters);
			} catch (final Exception e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error deleting Hard Disk statistics.", e);
			}
	 }

	 @Override
	 public Collection<HardDiskStatistics.Element> searchHardDiskElements(HardDiskParameters.SearchElementsParameter parameters) throws JeeObserverServerException {

			try {
				 return this.databaseHandlerHardDisk.searchElements(parameters);
			} catch (final Exception e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching Hard Disk elements.", e);
			}
	 }

	 @Override
	 public Collection<HardDiskStatistics> searchHardDiskStatistics(HardDiskParameters.SearchStatisticsParameter parameters) throws JeeObserverServerException {

			try {
				 return this.databaseHandlerHardDisk.searchStatistics(parameters);
			} catch (final Exception e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Error searching Hard Disk statistics.", e);
			}
	 }

	 //Settings
	 @Override
	 public Settings loadSettings() throws JeeObserverServerException {

			try {
				 return this.databaseHandlerSettings.loadSettings();

			} catch (final ClassNotFoundException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Unable to load settings entity from table. Read binary object failed.", e);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Unable to load settings entity from table.", e);
			}
	 }

	 @Override
	 public void updateSettings(Settings settings) throws JeeObserverServerException {

			try {
				 this.databaseHandlerSettings.updateSettings(settings);
			} catch (final IOException e) {
				 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage());
				 throw new JeeObserverServerException("Unable to insert/update settings entity into table. Write binary object failed.", e);
			}
	 }

	 static void fillBuffer(ByteBuffer buffer, SamplingStatistics statistics) {
			buffer.putLong(statistics.getDate().getTime());
			buffer.putInt(statistics.getCount());
	 }

	 static void fillBuffer(ByteBuffer buffer, DateStatistics statistics) {
			buffer.putLong(statistics.getMinimum().getTime());
			buffer.putLong(statistics.getMaximum().getTime());
	 }

	 static void fillBuffer(ByteBuffer buffer, NumberRangeStatistics statistics) {
			buffer.putDouble(statistics.getMinimum());
			buffer.putDouble(statistics.getMaximum());
			buffer.putDouble(statistics.getSum());
	 }

	 static void fillBuffer(ByteBuffer buffer, NumberStatistics statistics) {
			buffer.putDouble(statistics.getSum());
	 }

	 static NumberStatistics getNumberStatistics(ByteBuffer buffer) {
			return new NumberStatistics(buffer.getDouble());
	 }

	 static NumberRangeStatistics getNumberRangeStatistics(ByteBuffer buffer) {
			return new NumberRangeStatistics(buffer.getDouble(), buffer.getDouble(), buffer.getDouble());
	 }

	 static DateStatistics getDateStatistics(ByteBuffer buffer) {
			return new DateStatistics(new Date(buffer.getLong()), new Date(buffer.getLong()));
	 }

	 static class DatabaseHandlerTimerTask extends TimerTask {

			/** The Constant TIMER_INTERVAL. */
			public static final long TIMER_INTERVAL = 30 * 1000;// 30 Seconds

			private static Date lastTablesOptimizationDate = null;

			private static Date lastTablesCleanDate = null;

			@Override
			public void run() {

				 if (!JeeObserverServerContext.getInstance().isEnabled()) {
						return;
				 }

				 Settings settings;

				 try {
						settings = JeeObserverServerContext.getInstance().getDatabaseHandler().loadSettings();
				 } catch (final Exception e) {
						JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
						return;
				 }

				 final Date currentDate = new Date();

				 final TimeSchedule cleanTimeSchedule = settings.getTablesCleanSchedule();

				 if ((cleanTimeSchedule != null) && cleanTimeSchedule.isDateIntoSchedule(currentDate, DatabaseHandlerTimerTask.lastTablesCleanDate)) {

						DatabaseHandlerTimerTask.lastTablesCleanDate = new Date();

						JeeObserverServerContext.logger.log(Level.FINE, "Cleaning database.");

						// Clear actions
						Date date = settings.getActionMaxStoragePeriod().subtractToDate(new Date());

						JeeObserverServerContext.logger.log(Level.FINE, "Cleaning actions database. Deleting before {0}", date);

						try {
							 JeeObserverServerContext.getInstance().getDatabaseHandler().deleteActionStatistics(new ActionParameters.DeleteStatisticsParameter(null, date));
						} catch (final JeeObserverServerException e) {
							 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
						}

						// Clear JVM
						date = settings.getJvmMaxStoragePeriod().subtractToDate(new Date());

						JeeObserverServerContext.logger.log(Level.FINE, "Cleaning JVM database. Deleting before {0}", date);

						try {
							 JeeObserverServerContext.getInstance().getDatabaseHandler().deleteJvmStatistics(new JvmParameters.DeleteStatisticsParameter(null, date));
						} catch (final JeeObserverServerException e) {
							 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
						}

						// Clear HTTP Sessions
						date = settings.getHttpSessionMaxStoragePeriod().subtractToDate(new Date());

						JeeObserverServerContext.logger.log(Level.FINE, "Cleaning HTTP sessions database. Deleting before {0}", date);

						try {
							 JeeObserverServerContext.getInstance().getDatabaseHandler().deleteHttpSessionStatistics(new HttpSessionParameters.DeleteStatisticsParameter(null, date));
						} catch (final JeeObserverServerException e) {
							 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
						}

						// Clear Hard Disk
						date = settings.getHardDiskMaxStoragePeriod().subtractToDate(new Date());

						JeeObserverServerContext.logger.log(Level.FINE, "Cleaning Hard Disk database. Deleting before {0}", date);

						try {
							 JeeObserverServerContext.getInstance().getDatabaseHandler().deleteHardDiskStatistics(new HardDiskParameters.DeleteStatisticsParameter(null, date));
						} catch (final JeeObserverServerException e) {
							 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
						}
				 }

				 // Optimize database tables and indexes
				 final TimeSchedule optimizationTimeSchedule = settings.getTablesOptimizationSchedule();

				 if ((optimizationTimeSchedule != null) && optimizationTimeSchedule.isDateIntoSchedule(currentDate, DatabaseHandlerTimerTask.lastTablesOptimizationDate)) {

						DatabaseHandlerTimerTask.lastTablesOptimizationDate = new Date();

						JeeObserverServerContext.logger.log(Level.FINE, "Optimize free space from database");

						//TODO
			/*try {
						 JeeObserverServerContext.getInstance().getDatabaseHandler().optimizeDatabase();
						 } catch (final JeeObserverServerException e) {
						 JeeObserverServerContext.logger.log(Level.SEVERE, e.getMessage(), e);
						 }*/
				 }
			}
	 }
}